﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Text.RegularExpressions;
using ClipperHouse.jQuery.Base;
using System.Collections.Specialized;

namespace ClipperHouse.jQuery
{
	public static class Utility
	{
		/// <summary>
		/// Takes a string and attempts to parse it into most appropriate Javascript type. For example,
		/// the string "True" becomes true; "1.5" becomes 1.5. If it can't be parsed in an obvious way,
		/// it returns a string in quotes.
		/// </summary>
		/// <param name="paramAsString"></param>
		/// <returns></returns>
		public static string ToJSParam(this string paramAsString)
		{
			string cleanParam;

			bool paramIsFunction = paramAsString.StartsWith("function");

			bool paramIsParams = paramAsString.StartsWith("{");

			bool paramAsBool;
			bool paramIsBool = Boolean.TryParse(paramAsString, out paramAsBool);

			int paramAsInt;
			bool paramIsInt = Int32.TryParse(paramAsString, out paramAsInt);

			decimal paramAsDecimal;
			bool paramIsDecimal = Decimal.TryParse(paramAsString, out paramAsDecimal);

			if (paramIsFunction)
			{
				// Function should not have quotes
				cleanParam = paramAsString;
			}
			else if (paramIsParams)
			{
				// Params property list does not require quotes
				cleanParam = paramAsString;
			}
			else if (paramIsInt)
			{
				// Integer does not require quotes
				cleanParam = paramAsString;
			}
			else if (paramIsDecimal)
			{
				// Decimal does not require quotes
				cleanParam = paramAsString;
			}
			else if (paramIsBool)
			{
				// Boolean does not require quotes
				cleanParam = paramAsString.ToLower();
			}
			else
			{
				cleanParam = "\"" + paramAsString + "\"";
			}

			return cleanParam;
		}

		public static string ToSelectorString(this SelectorPrefix selectorPrefix)
		{
			string toString = selectorPrefix.ToString();

			if (selectorPrefix == SelectorPrefix.DollarSign)
			{
				toString = "$";
			}
			return toString;
		}
		
		/// <summary>
		/// Finds a Control recursively by its ID. Note: finds the first match and exits.
		/// From: http://www.west-wind.com/Weblog/posts/5127.aspx
		/// </summary>
		/// <param name="rootControl"></param>
		/// <param name="controlId"></param>
		/// <returns>First control matching Id</returns>
		public static Control FindControlRecursive(Control rootControl, string controlId)
		{
			if (rootControl.ID == controlId)
				return rootControl;

			foreach (Control control in rootControl.Controls)
			{
				Control foundControl = FindControlRecursive(control, controlId);
				if (foundControl != null)
				{
					return foundControl;
				}
			}

			return null;
		}

		/// <summary>
		/// Finds a Control recursively by its Type. Note: finds the first match and exits.
		/// From: http://www.west-wind.com/Weblog/posts/5127.aspx
		/// </summary>
		/// <param name="rootControl"></param>
		/// <param name="type"></param>
		/// <returns>First control matching Id</returns>
		public static Control FindControlRecursive(Control rootControl, Type type)
		{
			if (rootControl.GetType().Equals(type))
				return rootControl;

			foreach (Control control in rootControl.Controls)
			{
				Control foundControl = FindControlRecursive(control, type);
				if (foundControl != null)
				{
					return foundControl;
				}
			}

			return null;
		}

		public static string Indent(int numIndents, string indentString)
		{
			string result = String.Empty;

			for (int i = 0; i < numIndents; i++)
			{
				result += indentString;
			}

			return result;
		}

		public static string Indent(int numIndents)
		{
			return Indent(numIndents, "    ");
		}

		public static string ToScriptBlock(this string s)
		{
			string scriptBlock = String.Empty;

			if (!String.IsNullOrEmpty(s))
			{
				scriptBlock = Environment.NewLine +
					"<script type=\"text/javascript\">" + Environment.NewLine +
					s + Environment.NewLine +
					"</script>" + Environment.NewLine;
			}

			return scriptBlock;
		}

		/// <summary>
		/// Removes whitespace (spaces, line breaks and tabs) from beginning and end of a string
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public static string TrimWhitespace(this string s)
		{
			string result = s;

			if (result != null)
			{
				string regexPattern;
				Regex myRegex;

				// End of string
				regexPattern = @"[\r\n\t ]+$";
				myRegex = new Regex(regexPattern);
				result = myRegex.Replace(result, "");

				// Beginning of string
				regexPattern = @"^[\r\n\t ]+";
				myRegex = new Regex(regexPattern);
				result = myRegex.Replace(result, "");
			}

			return result;
		}

		/// <summary>
		/// Replaces all whitespace (tabs, line breaks, spaces) with a single space
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public static string WhitespaceToSpace(this string s)
		{
			string result = s.TrimWhitespace();

			if (result != null)
			{
				string regexPattern;
				Regex myRegex;

				// End of string
				regexPattern = @"[\r\n\t ]+";
				myRegex = new Regex(regexPattern);
				result = myRegex.Replace(result, " ");
			}

			return result;
		}

		public static string ToFunctionExpression(this string s)
		{
			return s.ToFunctionExpression(false);
		}

		public static string ToFunctionExpression(this string s, bool withLineBreaks)
		{
			return s.ToFunctionExpression(withLineBreaks, 0);
		}

		public static string ToFunctionExpression(this string s, bool withLineBreaks, int indent)
		{
			string result = s;

			if (result != null)
			{
				string lineBreak = String.Empty;
				if (withLineBreaks)
				{
					lineBreak = Environment.NewLine;
				}

				string indents = String.Empty;
				string closingIndents = String.Empty;

				if (indent > 0)
				{
					indents = Utility.Indent(indent);
					closingIndents = Utility.Indent(indent - 1);
				}

				result = "function() { " + lineBreak + indents + result + " " + lineBreak + closingIndents + "}";
			}

			return result;
		}

		public static string ToParamsExpression(this string s)
		{
			string result = s;

			if (result != null)
			{
				result = "{ " + result + " }";
			}

			return result;
		}

		/// <summary>
		/// Ensures that CSS unit such as 25px are passed to jQuery as "25px". jQuery must have non-numeric parameters in quotes.
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public static string CleanCssParamsList(this string s)
		{
			string result = s;

			if (result != null)
			{
				Regex hasAlphaRegex = new Regex(@"[A-Za-z\%\+\-\=]+");

				List<string> cssParamsInput = result.WhitespaceToSpace().Split(",".ToCharArray()).ToList();
				List<string> cssParamsOutput = new List<string>();

				foreach (string cssParam in cssParamsInput)
				{
					string[] nameValue = cssParam.Split(":".ToCharArray());
					bool isValid = nameValue.Length == 2;

					if (isValid)
					{
						string cssParamName = nameValue[0].TrimWhitespace();
						string cssParamValue = nameValue[1].TrimWhitespace();

						bool shouldBeQuoted = !cssParamValue.StartsWith("\"") && !cssParamValue.StartsWith("'") && hasAlphaRegex.IsMatch(cssParamValue);
						if (shouldBeQuoted)
						{
							cssParamValue = "\"" + cssParamValue + "\"";
						}

						string cssParamOutput = cssParamName + ": " + cssParamValue;
						cssParamsOutput.Add(cssParamOutput);
					}
				}

				result = String.Join(", ", cssParamsOutput.ToArray());
			}

			return result;
		}

		/// <summary>
		/// Wraps an existing function in $document.ready expression
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public static string ToDocumentReady(this string s, SelectorPrefix selectorPrefix)
		{
			NameValueCollection documentReadyParams = new NameValueCollection();
			documentReadyParams.Add("function", s.ToFunctionExpression(true));

			JQueryExpression documentReady = new JQueryExpression()
			{
				Selector = "document",
				SelectorPrefix = selectorPrefix,
				Method = TriggerEvent.Ready.ToString().ToLower(),
				Params = documentReadyParams,
				IsEnd = true
			};

			return documentReady.Javascript;
		}
	}
}
